package com.acumenvn.pent.Objects;
import com.acumenvn.pent.Utils.GameInformation;
import com.acumenvn.pent.Objects.CObject;
import com.acumenvn.pent.Objects.CRect;
import com.acumenvn.pent.Objects.CObjectsList;
import com.acumenvn.pent.Objects.Node;


public class CQuadTree {
	// Variables
	public CQuadNode m_root;
	public float m_fX;
	public float m_fY;
	
	/**********************************************
	 *					CONSTRUCTOR
	 **********************************************/
	public CQuadTree() {
		// TODO Auto-generated constructor stub
	}
	
	public CQuadTree(float width, float height) {
		m_root = new CQuadNode(GameInformation.getInstance().getSizeTile()*-1,0,width,height);
		m_fX = 0;
		m_fY = 0;
	}
	
	/**********************************************
	 *					PUBLIC METHODS
	 **********************************************/
	public void addObject(CQuadNode node, CObject object) {
		if(node != null) {
			node.m_count++;
			float topBottom = node.m_rect.getTop() + node.m_rect.getBottom();
			float leftRight = node.m_rect.getLeft() + node.m_rect.getRight();
			CRect tempRect = new CRect();
			// Check in Top Left Node
			tempRect.setTop(node.m_rect.getTop());
			tempRect.setBottom(topBottom);
			tempRect.setLeft(node.m_rect.getLeft());
			tempRect.setRight(leftRight);
			// Check Temp rect stays in another rect
			if(CRect.checkStayInsideAnotherRect(object.m_workingArea, tempRect) && node.m_level < 5) {
				if(node.m_topLeft == null) {
					node.m_topLeft = new CQuadNode(tempRect);
				}
				node.m_topLeft.m_level = node.m_level + 1;
				addObject(node.m_topLeft, object);
				return;
			}
			
			// Check In Bottom Left
			tempRect.setTop(topBottom);
			tempRect.setBottom(node.m_rect.getBottom());
			tempRect.setLeft(node.m_rect.getLeft());
			tempRect.setRight(leftRight);
			// Check TEMP rect stays in another rect
			if(CRect.checkStayInsideAnotherRect(object.m_workingArea, tempRect) && node.m_level < 5) {
				if(node.m_bottomLeft == null) {
					node.m_bottomLeft = new CQuadNode(tempRect);
				}
				node.m_bottomLeft.m_level = node.m_level + 1;
				addObject(node.m_bottomLeft, object);
				return;
			}
			// Check in Right top
			tempRect.setTop(node.m_rect.getTop());
			tempRect.setBottom(topBottom);
			tempRect.setLeft(leftRight);
			tempRect.setRight(node.m_rect.getRight());
			
			// Check TEMP rect stays in another rect
			if(CRect.checkStayInsideAnotherRect(object.m_workingArea, tempRect) && node.m_level < 5) {
				if(node.m_topRight == null) {
					node.m_topRight = new CQuadNode(tempRect);
				}
				node.m_topRight.m_level = node.m_level + 1;
				addObject(node.m_topRight, object);
				return;
			}
			
			// Check in Bottom Right
			tempRect.setTop(topBottom);
			tempRect.setBottom(node.m_rect.getBottom());
			tempRect.setLeft(leftRight);
			tempRect.setRight(node.m_rect.getRight());
			// Check TEMP rect stays in another rect
			if(CRect.checkStayInsideAnotherRect(object.m_workingArea, tempRect) && node.m_level < 5) {
				if(node.m_bottomRight == null) {
					node.m_bottomRight = new CQuadNode(tempRect);
				}
				node.m_bottomRight.m_level = node.m_level + 1;
				addObject(node.m_bottomRight, object);
				return;
			}
			
			// Assign object
			node.m_objectsList.addNode(object);
		}
	}
	
	public void addObject(CObject object) {
		addObject(m_root, object);
	}
	
	public void free(CQuadNode node) {
		node.m_objectsList.m_count = 0;
		if(node.m_topLeft != null) {
			free(node.m_topLeft);
		}
		
		if(node.m_topRight != null) {
			free(node.m_topRight);
		}
		
		if(node.m_bottomLeft != null) {
			free(node.m_bottomLeft);
		}
		
		if(node.m_bottomRight != null) {
			free(node.m_bottomRight);
		}
	}
	
	public void free() {
		free(m_root);
	}
	
	public void setHealth(CQuadNode node) {
		Node temp = node.m_objectsList.m_head;
		while(temp != null) {
			temp.m_object.m_health = 1;
			temp.m_object.m_rect = new CRect(temp.m_object.m_fX, temp.m_object.m_fY, (float)temp.m_object.m_iWidth, (float)temp.m_object.m_iHeight);
			if(temp.m_object.m_style == GameInformation.getInstance().getUnit_Destruction()) {
				temp.m_object.m_vX = 0;
				temp.m_object.m_fY = 0;
			}
			temp = temp.m_nextNode;
		}
		
		if(node.m_topLeft != null) {
			setHealth(node.m_topLeft);
		}
		
		if(node.m_bottomLeft != null) {
			setHealth(node.m_bottomLeft);
		}
		
		if(node.m_topRight != null) {
			setHealth(node.m_topRight);
		}
		
		if(node.m_bottomRight != null) {
			setHealth(node.m_bottomRight);
		}
	}
	
	public void setHealth() {
		setHealth(m_root);
	}
	
	public void setObjectsList(CObjectsList objectsList, CRect rect) {
		addObjectInRect(objectsList,m_root,rect);
	}
	/**********************************************
	 *					STATIC METHODS
	 **********************************************/
	public static void addObjectInRect(CObjectsList objectsList,CQuadNode node, CRect rect) {
		if(node != null)
		{
			if(CRect.checkCollisionBetween2Rect(rect,node.m_rect))
			{
				if(node.m_objectsList.m_head != null)
				{
					objectsList.addList(node.m_objectsList);
				}
				addObjectInRect(objectsList,node.m_topLeft,rect);
				addObjectInRect(objectsList,node.m_bottomLeft,rect);
				addObjectInRect(objectsList,node.m_topRight,rect);
				addObjectInRect(objectsList,node.m_bottomRight,rect);
			}
		}
	}
	
	public static Boolean checkNodeCollideWithList(Node node,CObjectsList objectsList) {
		Node temp = objectsList.m_head;		
		while (temp != objectsList.m_tail.m_nextNode)
		{
			if(temp.m_object.m_canCollide == true &&
				temp.m_object.m_health > 0 &&
				temp.m_object.m_style > GameInformation.getInstance().getUnit_Blank() &&
				CRect.checkCollisionBetween2Rect(node.m_object.m_rect,temp.m_object.m_rect) &&
				node != temp)
			{
				return true;
			}
			temp = temp.m_nextNode;
		}
		return false;
	}
	public static Boolean checkRectCollideWithList(CRect rect, CObjectsList objectsList) {
		Node temp = objectsList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_canCollide == true &&
				temp.m_object.m_health > 0 &&
				temp.m_object.m_style > '0' &&
				CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return true;
			}
			temp = temp.m_nextNode;
			// if temp node reach to the end of list
			// so  exit while loop
			if(temp == objectsList.m_tail.m_nextNode)
			{
				break;
			}
		}
		return false;
	}
	
	public static Boolean checkRectCollideWithList(CRect rect, CObjectsList objectsList, char style) {
		Node temp = objectsList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_canCollide == true &&
				temp.m_object.m_health > 0  &&
				temp.m_object.m_style == style &&
				CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return true;
			}
			temp = temp.m_nextNode;
		}
		return false;
	}
	
	public static CObject objectCheckRectWithList(CRect rect, CObjectsList objectsList) {
		Node temp = objectsList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_canCollide == true &&
				 temp.m_object.m_health > 0		&&
				 temp.m_object.m_style != GameInformation.getInstance().getUnit_Blank() &&
				CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return temp.m_object ;
			}
			temp = temp.m_nextNode;
		}
		return null;
	}
	
	public static CObject objectCheckRectWithList(CRect rect, CObjectsList objectList, char style) {
		Node temp = objectList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_style == style &&
				 temp.m_object.m_health > 0 &&
				CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return temp.m_object;
			}
			temp = temp.m_nextNode;
		}
		return null;
	}
	
	public static CObject objectCheckRectWithListCut(CRect rect, CObjectsList objectsList) {
		Node temp = objectsList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_canBeDestroyed == true &&
				temp.m_object.m_health > 0		&&
				temp.m_object.m_style != GameInformation.getInstance().getUnit_Blank() &&
				CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return temp.m_object ;
			}
			temp = temp.m_nextNode;
		}
		return null;
	}
	
	public static CObject objectCheckRectWithListCheckItems(CRect rect, CObjectsList objectsList) {
		Node temp = objectsList.m_head;
		while(temp != null)
		{
			if(temp.m_object.m_checkedItem == true &&
				temp.m_object.m_health > 0 &&
				temp.m_object.m_style != GameInformation.getInstance().getUnit_Blank() &&
			CRect.checkCollisionBetween2Rect(rect,temp.m_object.m_rect))
			{
				return temp.m_object;
			}
			temp = temp.m_nextNode;
		}
		return null;
	}
}
